<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Behavior;
use Think\Log;
/**
 * 系统行为扩展：页面Trace显示输出
 */
class ShowPageTraceBehavior {
    protected $tracePageTabs =  array('BASE'=>'基本','SYSTEM'=>'系统','FILE'=>'文件','INFO'=>'流程','ERR'=>'错误','SQL'=>'SQL','DEBUG'=>'调试');

    // 行为扩展的执行入口必须是run
    public function run(&$params){
        
        // 禁止 trace 输出
        return;
        
        if(!IS_AJAX && !IS_CLI && C('SHOW_PAGE_TRACE')&&$this->checkUA()) {
            echo $this->showTrace();
        }
    }

    /**
     * 显示页面Trace信息
     * @access private
     */
    private function showTrace() {
        $show_trace_tabs=defined('TRACE_TABS')?explode(',',TRACE_TABS):array();
         // 系统默认显示信息
        $files  =  get_included_files();
        $info   =   array();
        foreach ($files as $key=>$file){
            $info[] = $file.' ( '.number_format(filesize($file)/1024,2).' KB )';
        }
        $trace  =   array();
        $base   =   array(
            '请求信息'  =>  date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.__SELF__,
            '运行时间'  =>  $this->showTime(),
            '内存开销'  =>  MEMORY_LIMIT_ON?number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1048576,2).' M':'不支持',
            '查询信息'  =>  N('db_query').'次查询 '.N('db_write').'次写入 ',
            '缓存信息'  =>  N('cache_read').'次查询 '.N('cache_write').'次写入 ',
            '文件加载'  =>  count(get_included_files()),
            '配置加载'  =>  count(C()),
            '吞吐率'	=>	number_format(1/G('beginTime','viewEndTime'),2).'req/s',
            '会话信息'  =>  'SESSION_ID='.session_id(),
            );
        // 读取应用定义的Trace文件
        $traceFile  =   COMMON_PATH.'Conf/trace.php';
        if(is_file($traceFile)) {
            $base   =   array_merge($base,include $traceFile);
        }
        $debug  =   trace();
        $tabs   =   C('TRACE_PAGE_TABS',null,$this->tracePageTabs);
        foreach ($tabs as $name=>$title){
            if($show_trace_tabs&&!in_array($name,$show_trace_tabs))continue;
            switch(strtoupper($name)) {
                case 'BASE':// 基本信息
                    $trace[$title]  =   $base;
                    break;
                case 'SYSTEM'://框架系统相关信息
                    $trace[$title] = $this->showSysInfo();
                    break;
                case 'FILE': // 文件信息
                    $trace[$title]  =   $info;
                    break;
                case 'SQL':
                    $trace[$title]=$this->formtSql($debug[$name]);
                    break;
                case 'ERR':
                    $name="ERR|NOTICE";
                    //继续默认处理
                default:// 调试信息
                    $name       =   strtoupper($name);
                    if(strpos($name,'|')) {// 多组信息
                        $array  =   explode('|',$name);
                        $result =   array();
                        foreach($array as $name){
                            $result   +=   isset($debug[$name])?$debug[$name]:array();
                        }
                        $trace[$title]  =   $result;
                    }else{
                        $trace[$title]  =   isset($debug[$name])?$debug[$name]:'';
                    }
            }
        }
        if($save = C('PAGE_TRACE_SAVE')) { // 保存页面Trace日志
            if(is_array($save)) {// 选择选项卡保存
                $tabs   =   C('TRACE_PAGE_TABS',null,$this->tracePageTabs);
                $array  =   array();
                foreach ($save as $tab){
                    $array[] =   $tabs[$tab];
                }
            }
            $content    =   date('[ c ]').' '.get_client_ip().' '.$_SERVER['REQUEST_URI']."\r\n";
            foreach ($trace as $key=>$val){
                if(!isset($array) || in_array($key,$array)) {
                    $content    .=  '[ '.$key." ]\r\n";
                    if(is_array($val)) {
                        foreach ($val as $k=>$v){
                            $content .= (!is_numeric($k)?$k.':':'').print_r($v,true)."\r\n";
                        }
                    }else{
                        $content .= print_r($val,true)."\r\n";
                    }
                    $content .= "\r\n";
                }
            }
            error_log(str_replace('<br/>',"\r\n",$content), 3,C('LOG_PATH').date('y_m_d').'_trace.log');
        }
        unset($files,$info,$base);
        // 调用Trace页面模板
        ob_start();
        include C('TMPL_TRACE_FILE')?C('TMPL_TRACE_FILE'):THINK_PATH.'Tpl/page_trace.tpl';
        return ob_get_clean();
    }

    /**
     * 获取运行时间
     */
    private function showTime() {
        // 显示运行时间
        G('beginTime',$GLOBALS['_beginTime']);
        G('viewEndTime');
        // 显示详细运行时间
        return ($this->formtTime(G('beginTime','viewEndTime'))).
                ' ( 加载:'.$this->formtTime(G('beginTime','loadTime')).
                ' 初始化:'.$this->formtTime(G('loadTime','initTime')).
                ' 执行:'.$this->formtTime(G('initTime','viewStartTime')).
                ' 模板:'.
                $this->formtTime(G('viewStartTime','viewEndTime')).
                ' )';
    }
    
    /**
     * 格式化SQLtrace信息
     */
    private function formtSql($sqlInfo){
        $writeSqls[]="SQL概况:".N('db_query').'次查询 '.N('db_write').'次写入 ';
        $writeSqls[]="写操作：";
        $querySqls[]="读操作：";
        foreach($sqlInfo as $sql){
            if(strpos($sql,"SELECT")===0||strpos($sql,'SHOW')===0||strpos($sql,'DESC')===0){
                $querySqls[]=$sql;
            }else{
                $writeSqls[]=$sql;
            }
        }
        return array_merge($writeSqls,$querySqls);
    }
    
    /*
     * 格式化时间显示
     */
    private function formtTime($time){
        return $time>1?($time.'s'):(($time*1000).'ms');
    }
    
    /*
     * 获取当前框架系统相关信息
     */
    private function showSysInfo(){
        $info=array(
            'DEBUG'=>APP_DEBUG?'开启':'关闭',
            '模块'=>MODULE_NAME,
            '控制器'=>CONTROLLER_NAME,
            'ACTION'=>ACTION_NAME,
            'GET'=>json_encode($_GET),
            'POST'=>json_encode(I('post.'))
        );
        return $info;
    }
    
    /**
     * 检测UA
     */
    private function checkUA(){
        $traceUA=defined('TRACE_UA')?TRACE_UA:"KC_DEBUG_TRACE";
        return strpos($_SERVER['HTTP_USER_AGENT'],$traceUA)!==false;
    }
}
